module Text.ParserCombinators.Table.TypeParser (parseInteger,
                                                parseFloat,
                                                integerParser,
                                                floatParser) where 


import Text.ParserCombinators.Parsec
import Data.Char

parseInteger :: (Integral a) => String -> Either String a
parseInteger = runP $ do
  i <- integerParser
  eof
  return i

parseFloat :: String -> Either String Double
parseFloat = runP $ do
  f <- floatParser
  eof
  return f

runP p s = let r = parse p "" s
           in case r of
             Left e -> Left $ show e
             Right x -> Right x
    
sign :: (Num a) => Parser (a -> a) 
sign = do
  x <- option '+' $ oneOf "+-"
  return $ case x of
    '+' -> id
    '-' -> negate

integerParser :: (Integral a) => Parser a
integerParser = do
    s <- sign
    d <- many1 digit
    let numeric = foldl (\a b -> 10*a + b) 0 $ map (fromInteger . toInteger . digitToInt) d
    return $ s $ numeric

floatParser :: Parser Double
floatParser = do
    s <- sign
    (i, f) <- try ( do { i <- many1 digit;
                         char '.';
                         f <- many1 digit;
                         return (i, f) } )
              <|> try ( do { i <- many1 digit;
                             try (char '.') <|> lookAhead (oneOf "EeDd");
                             return (i, []) } )
              <|> do { char '.';
                       f <- many1 digit;
                       return ([], f) }

    exp <- option 0.0 $ do { oneOf "EeDd";
                             i <- integerParser;
                             return $ fromInteger i }

    let digitsToNum = map (fromInteger . toInteger . digitToInt)
    let integral_part = foldl (\a b -> 10.0*a + b) 0.0 $ digitsToNum i
    let fractional_part = foldr (\a b -> a + 0.1*b) 0.0 $ digitsToNum ('0':f)
    let x = s $ (integral_part + fractional_part) * 10.0**exp 
    return x
